using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace MonoCash.ObjectModel
{
    class ObjectModel 
    {
        private string TableName = "";
        protected bool ObjectIsConstructed = false;
        public ObjectModel()
        {
            TableName = GetTableName();
            ObjectIsConstructed = true;
        }
        public ObjectModel(object objectId)
        {
            TableName = GetTableName();
            int objectInt = Convert.ToInt32(objectId);
            if (objectInt != -1)
            {
                DataRow existingData = GetExistingRow(objectInt);

                foreach (DataColumn col in existingData.Table.Columns)
                {
                    object value = existingData[col.ColumnName];
                    string columnName = col.ColumnName;
                    try
                    {
                        if (!col.ReadOnly)//Calculated columns are read directly in their associated Property
                        {
                            GetType().GetProperty(columnName).SetValue(this, value, null);
                        }
                    }
                    catch (Exception ex) 
                    {
                        Console.WriteLine("Error reading record\n" + ex.Message);
                    }
                }
            }
            ObjectIsConstructed = true;
        }
        public ExtendedProperty.ExtendedPropertyCollection ExtendedProperties
        {
            get
            {
                return new ExtendedProperty.ExtendedPropertyCollection(GetTableName(), ID);
            }
        }
        private string GetTableName()
        {
            string tableName = GetType().Name;
            if (tableName.EndsWith("y"))
            {
                tableName = tableName.Substring(0, tableName.Length - 1) + "ie";
            }
            tableName += "s";
            return tableName;
        }

        public virtual void SyncToBackend()
        {
            if (ObjectIsConstructed)
            {
                DataRow row = Program.AppSettings.Data.GetDataTable(TableName).NewRow();

                //Remove existing row
                try
                {
                    if (ID != -1)
                    {
                        
                        row =  GetExistingRow(ID);
                    }
                }
                catch { }

                foreach (System.Reflection.PropertyInfo pi in GetType().GetProperties())
                {
                    if (!pi.PropertyType.FullName.Contains("ObjectModel") && row.Table.Columns.Contains(pi.Name))
                    {
                        object value = pi.GetValue(this, null);
                        if (!(pi.Name.Equals("ID") && Convert.ToInt32(value) == -1))// -1 signals new row
                        {
                            if (!row.Table.Columns[pi.Name].ReadOnly)
                            {
                                row[pi.Name] = value;
                            }
                        }
                    }
                }
                try
                {
                    if (ID == -1)
                    {
                        Program.AppSettings.Data.GetDataTable(TableName).Rows.Add(row);
                        //Update ID with new value for inserted rows
                        ID = int.Parse(row["ID"].ToString());
                    }
                }
                catch { }
            }
        }
        internal DataRow GetExistingRow(int rowId)
        {
            DataTable table = Program.AppSettings.Data.GetDataTable(TableName);
            DataRow[] existingRows = table.Select("ID=" + rowId.ToString());
            DataRow returnValue = table.NewRow();
            if (existingRows.Length > 0)
            {
                returnValue = existingRows[0];
            }
            return returnValue;
        }
        /// <summary>
        /// Deletes item without verifying it is in use. The data backend should enforce referential integrity.
        /// </summary>
        public void Delete()
        {
            try
            {
                GetExistingRow(ID).Delete();
                id = -1;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unable to delete item\n" + ex.Message);
            }
        }
        public List<ObjectModel> Objects
        {
            get
            {
                List<ObjectModel> temp = new List<ObjectModel>();
                foreach (DataRow row in Program.AppSettings.Data.GetDataTable(TableName).Rows)
                {
                    object[] parameters = { row["ID"] };
                    temp.Add((ObjectModel)Activator.CreateInstance(GetType(), parameters));
                }
                return temp;
            }
        }
        private int id = -1;
        public int ID
        {
            get { return id; }
            set {//ID's should not be SyncToBackend()'d.  
                id = value; }
        }

        public string DefaultDisplayValue
        {
            get
            {
                string temp = this.ID.ToString();

                switch (this.GetType().Name)
                {
                    case "Account":
                        Account a = (Account)this;
                        temp = a.LongName;
                        break;
                    case "Currency":
                        Currency c = (Currency)this;
                        temp = c.Symbol;
                        break;
                    case "Security":
                        Security s = (Security)this;
                        temp = s.Symbol;
                        break;
                    default:
                        try
                        {
                            temp = this.GetType().GetProperty("Name").GetValue(this, null).ToString();
                        }
                        catch { }
                        break;
                }
                return temp;
            }
        }

        public override bool Equals(object obj)
        {
            bool result = false;
            try
            {
               ObjectModel other = (ObjectModel)obj;
               result = other.ID == ID;
            } catch {}//Non ObjectModel types will be false
            return result;
        }
        public override int GetHashCode()
        {
            return ID;
        }

    }
}
